package com.lbh.structures.math;

import com.alibaba.fastjson.annotation.JSONField;
import com.sun.jna.Structure;

import java.util.Arrays;
import java.util.List;

/***
 * project:JRuntime
 * package:com.lbh.structures
 *
 * @author user:lenovo QQ:1601078366
 * @date 2021/10/18 0:17
 * @version V1.0
 */
@SuppressWarnings({"MethodDoesntCallSuperMethod", "unused", "AlibabaConstantFieldShouldBeUpperCase"})
public class Quaternion implements Cloneable {

    @JSONField(name = "x")
    public float x;
    @JSONField(name = "y")
    public float y;
    @JSONField(name = "z")
    public float z;
    @JSONField(name = "w")
    public float w;

    public static final Quaternion none = new Quaternion(1.0F, 0.0F, 0.0F, 0.0F);

    public Quaternion(){
        x = 0.0F; y = 0.0F; z = 0.0F; w = 1.0F;
    }

    public Quaternion(Vector3 v, float w){
        x = v.x; y = v.y; z = v.z; this.w = w;
    }

    public Quaternion(float w, float x, float y, float z){
        this.x = x; this.y = y; this.z = z; this.w = w;
    }

    @Override
    public Quaternion clone() {
        return new Quaternion(w, x, y, z);
    }

    public float magnitude(){
        return Mathf.sqrt(w * w + x * x + y * y + z * z);
    }

    public float magnitudeSqr(){
        return w * w + x * x + y * y + z * z;
    }

    public Quaternion mul(float x){
        this.x *= x; y *= x; z *= x; w *= x;
        return this;
    }

    public Quaternion mul(Quaternion q){
        float nx, ny, nz, nw;
        nx = w * q.x + x * q.w + y * q.z - z * q.y;
        ny = w * q.y - x * q.z + y * q.w + z * q.x;
        nz = w * q.z + x * q.y - y * q.x + z * q.w;
        nw = w * q.w - x * q.x - y * q.y - z * q.z;
        w = nw; x = nx; y = ny; z = nz;
        return this;
    }

    public Quaternion div(float x){
        float div = 1.0F / x;
        this.x *= div; y *= div; z *= div; w *= div;
        return this;
    }

    public Vector3 toAxis(){
        return new Vector3(x, y, z);
    }

    public Quaternion conjugate(){
        return new Quaternion(-x, -y, -z, w);
    }

    public Quaternion inverse(){
        return new Quaternion(-x, -y, -z, w).div(magnitudeSqr());
    }

    public Quaternion normal(){
        float div = 1.0F / magnitude();
        return new Quaternion(w * div, x * div, y * div, z * div);
    }

    public Quaternion normalize(){
        float div = 1.0F / magnitude();
        w *= div; x *= div; y *= div; z *= div;
        return this;
    }

    public static Quaternion axisAngle(Vector3 axis, float angle) {
        angle *= 0.00872664625997164788461845384244F;
        return new Quaternion(axis.normal().mul(Mathf.sin(angle)), Mathf.cos(angle));
    }
}
